package org.cedar.syntaxcore;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;

import org.cedar.exceptions.CalcException;

/**
 * <p>Title: 运算单元包装类</p>
 * <p>Description:
 * 公式列表
 * 文本文件
 * 输入流
 * 文本：批量对公式进行处理
 * eg.
 * [zb1]=[zb2] + [zb3]
 * [zb5]=[zb1] + [zb5]
 * [zb4]=[zb2] + [zb4]
 * 公式按顺序执行。
 * </p>
 *
 * <p>Copyright: Copyright (c) 2005</p>
 *
 * <p>Company: net.wzh</p>
 *
 * @author wzh
 * @version 1.0
 */
public class FormulaUtil {
	private String[] surroundChar = new String[]{"{}","\'\'","\"\"","[]","()"};
    private SyntaxContext ctx;
    public FormulaUtil() {
        super();
    }

    public FormulaUtil(SyntaxContext ctx) {
        this.ctx = ctx;
    }


    public void process(InputStream is) throws CalcException, IOException {
        InputStreamReader isr = new InputStreamReader(is);
        BufferedReader br = new BufferedReader(isr);
        String aLine = null;
        Calculator cal = new Calculator(this.ctx);
        Parser parser = new Parser();
        StringBuilder sb = new StringBuilder();
        while ((aLine = br.readLine()) != null) {
        	sb.append(aLine.trim());
        }
        process(sb.toString(), parser, cal);
        cal = null;
        parser = null;
    }

    public void process(File file) throws CalcException, IOException {
        process(new FileInputStream(file));
    }

    public void process(List expList) throws CalcException {
        if (null != expList) {
            Calculator cal = new Calculator(this.ctx);
            Parser parser = new Parser();
            for (int i = 0; i < expList.size(); i++) {
            	process((String) expList.get(i), parser, cal);
            }
            cal = null;
            parser = null;
        }
    }

    public MetaElement execute(String syntax)throws CalcException {
    	Calculator cal = new Calculator(this.ctx);
        Parser parser = new Parser();
        MetaElement ret = process(syntax,parser,cal);
        cal = null;
        parser = null;
        return ret;
    }


    ///处理单行
    private MetaElement process(String exp, Parser parser, Calculator cal) throws
            CalcException {
    	LineProcess lp = new LineProcess();
        lp.setLineInfo(exp, ';');
        lp.setNotSurroundChar(surroundChar);
        MetaElement ret = null;
        while (lp.hasMoreElements()) {
        	String syn = lp.next().trim();
        	if("".equals(syn))
        		continue;
        	if(isIfClause(syn,0))
        		processIfClause(syn,0,parser,cal);
        	else if(isWhileClause(syn, 0))
        		processWhileClause(syn,0,parser,cal);
        	else
        		parser.parseIt(syn);
            ret = cal.calcIt(parser.eqResult);
        }
        lp = null;
        return ret;
    }
    public SyntaxContext getContext(){
    	return this.ctx;
    }
    private boolean isIfClause(String strSrc, int pos){
    	return (strSrc.charAt(pos) == 'i' || strSrc.charAt(pos) == 'I')
    	&& pos+1 < strSrc.length()
    	&& (strSrc.charAt(pos + 1) == 'f' || strSrc.charAt(pos + 1) == 'F');
    }
    
    private boolean isWhileClause(String strSrc, int pos){
    	return (strSrc.charAt(pos) == 'w' || strSrc.charAt(pos) == 'W')
    	&& pos+4 < strSrc.length()
    	&& "while".equals(strSrc.substring(pos, pos+5).toLowerCase());
    }
    
    private MetaElement processWhileClause(String strSrc, int pos, Parser parser, Calculator cal)throws CalcException{
    	if(null == strSrc || "".equals(strSrc.trim()))
    		return null;
    	strSrc = strSrc.trim();
    	int lrBr = 1;
    	int len = strSrc.length();
    	if(isWhileClause(strSrc, pos))
    		pos+=5;
    	else{
    		return process(strSrc,parser,cal);
    	}
    	int pos0  = pos;
    	int pos1 = pos;//往前探索'{'和'}'对,依次判断if结构是否满足要求
    	while(++pos1 < len){
    		if(strSrc.charAt(pos1) == '{'){
    			pos0 = pos1;
    			break;
    		}
    	}
    	pos1++;
    	while ( (pos1 < len)) {
    		switch (strSrc.charAt(pos1)) {
    		case '{':
    			lrBr++;
    			break;
    		case '}':
    			lrBr--;
    			break;
    		}
    		pos1++;
    		if (lrBr == 0)
    			break;
    	}
    	if(lrBr != 0){
    		throw new CalcException(2001);
    	}
    	MetaElement ret = null;
    	while(Boolean.TRUE.equals(process(strSrc.substring(pos, pos0),parser,cal).value)){
    		ret = process(strSrc.substring(pos0+1, pos1-1),parser,cal);
    	}
    	return ret;
    }
    //增加控制结构 if condition {} else {}
    private MetaElement processIfClause(String strSrc, int pos, Parser parser, Calculator cal)throws CalcException{
    	if(null == strSrc || "".equals(strSrc.trim()))
    		return null;
    	strSrc = strSrc.trim();
    	int lrBr = 1;
    	int len = strSrc.length();
        if(isIfClause(strSrc, pos))
        	pos+=2;
        else{
        	return process(strSrc,parser,cal);
        }
        int pos0  = pos;
        int pos1 = pos;//往前探索'{'和'}'对,依次判断if结构是否满足要求
        while(++pos1 < len){
        	if(strSrc.charAt(pos1) == '{'){
        		pos0 = pos1;
        		break;
        	}
        }
        pos1++;
        while ( (pos1 < len)) {
          switch (strSrc.charAt(pos1)) {
            case '{':
        	  lrBr++;
        	  break;
            case '}':
              lrBr--;
              break;
          }
          pos1++;
          if (lrBr == 0)
            break;
        }
        if(lrBr != 0){
        	throw new CalcException(2002);
        }
        MetaElement ret = process(strSrc.substring(pos, pos0),parser,cal);
        if(Boolean.TRUE.equals(ret.value)){
        	return process(strSrc.substring(pos0+1, pos1-1),parser,cal);
        }
        //judge else if
        pos1 = escapeSpace(strSrc, pos1);
        while(pos1 < len && !('e' == strSrc.charAt(pos1) || 'E' == strSrc.charAt(pos1))){
        	pos1++;
        	if(' ' != strSrc.charAt(pos1))
        		throw new CalcException(2002);
        }
        if(pos1+4 < len && "else".equalsIgnoreCase(strSrc.substring(pos1, pos1 + 4))){
        	int np = escapeSpace(strSrc, pos1 + 4);
        	if(np+1 < len){
        		if('{' == strSrc.charAt(np)){
        		 pos1 = np+1;
        		 lrBr = 1;
        		 while ( (pos1 < len)) {
        	          switch (strSrc.charAt(pos1)) {
        	            case '{':
        	        	  lrBr++;
        	        	  break;
        	            case '}':
        	              lrBr--;
        	              break;
        	          }
        	          pos1++;
        	          if (lrBr == 0)
        	            break;
        	        }
        	        if(lrBr != 0){
        	        	throw new CalcException(2002);
        	        }
        	        return process(strSrc.substring(np+1, pos1-1), parser,cal);
        		}else if(isIfClause(strSrc,np)){
        			return processIfClause(strSrc,np,parser,cal);
        		}else{
        			return process(strSrc.substring(np),parser,cal);
        		}
        	}
        }
        return null;
    }
    private int escapeSpace(String src, int pos){
    	int len = src.length();
    	while(pos < len && (src.charAt(pos) == ' ' || src.charAt(pos) == '\n'  || src.charAt(pos) == '\r' || src.charAt(pos) == '\t' )){
    		pos++;
    	}
    	return pos;
    }
}
